package com.tourism.user.cn.service.impl;
/*********************************************************************
 Copyright(c) 2024 All Rights Reserved .
 Author : liliang
 CreatedOn : 2024/12/27 21:33
 Email : 2061996582@qq.com
 Describe : TODO
 UseCase :
 Version : 2024|V1.0.0.0
 **********************************************************************/

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.tourism.user.cn.service.SmsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * @author new
 * @date 2024/12/27 21:33
 */
@Slf4j
@Service
public class SmsServiceImpl implements SmsService {
    @Autowired
    private RedisTemplate redisTemplate;

    // Redis中验证码的key前缀
    //用于存储验证码本身,key格式：sms:code:手机号，value是验证码,有效期5分钟（CODE_EXPIRE_MINUTES）
    private static final String SMS_CODE_PREFIX = "sms:code:";
    // Redis中发送记录的key前缀
    //用于存储发送记录,key格式：sms:send:手机号，value是1，有效期60秒（SEND_INTERVAL_SECONDS）
    private static final String SMS_SEND_PREFIX = "sms:send:";
    // 验证码有效时间（单位：分钟）
    private static final long CODE_EXPIRE_MINUTES = 5;
    // 发送冷却时间（秒）
    private static final long SEND_INTERVAL_SECONDS = 60;


    @Override
    public boolean sendSms(String mobile) {

        String sendKey = SMS_SEND_PREFIX + mobile;
        //检查手机验证码是否在冷却时间内
        //使用Redis中的setnx命令，将手机号当成Key，如果Key不存在则设置值为1，并设置冷却时间为60秒，也就是说用户无法再60秒内重复获取验证码
        //如果Key存在，则返回false，表示用户在冷却时间内无法再次获取验证码
        //如果Key不存在，则返回true
        Boolean notCoolDown = redisTemplate.opsForValue().setIfAbsent(
                sendKey,
                "1",
                SEND_INTERVAL_SECONDS,
                TimeUnit.SECONDS
        );

        //notCoolDown 是一个 Boolean 对象（不是基本类型 boolean）
        //Boolean 对象可能有三种值：false，true，null
        if (Boolean.FALSE.equals(notCoolDown)) {
            //记录日志
            log.info("手机号{}发送验证码过于频繁", mobile);
            return false;
        }

        try {
            //生成随机六位数验证码
            String code = RandomUtil.randomNumbers(6);
            //将验证码存入redis并设置过期时间
            String codeKey = SMS_CODE_PREFIX + mobile;
            redisTemplate.opsForValue().set(
                    codeKey,
                    code,
                    CODE_EXPIRE_MINUTES,
                    TimeUnit.MINUTES
            );

            // TODO 调用短信服务发送短信

            log.info("向手机号{}发送验证码：{}", mobile, code);

            return true;
        } catch (Exception e) {
            log.error("发送验证码失败，手机号：{}，原因：{}", mobile, e.getMessage());
            redisTemplate.delete(sendKey);
            return false;
        }
    }

    @Override
    public boolean verifyCode(String mobile, String code) {
        // TODO 验证验证码
        //判断手机号、验证码是否为空，为空直接返回false
        log.info("验证码验证，手机号：{}，验证码：{}", mobile, code);
        if (StrUtil.isBlank(mobile) || StrUtil.isBlank(code)) {
            return false;
        }

        //获取验证码
        String smsCode = (String) redisTemplate.opsForValue().get(SMS_CODE_PREFIX + mobile);
        log.info("验证码：{}", smsCode);


        //判断验证码是否正确
        if (StrUtil.isBlank(smsCode) || !smsCode.equals(code)) {
            return false;
        }

        //删除验证码
        redisTemplate.delete(SMS_CODE_PREFIX + mobile);
        return true;
    }
}
